package air.jason.com.porterduffxfermodetest.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import air.jason.com.porterduffxfermodetest.R;

/**
 * @DESC:
 * @Author: Jason
 * @Date: 16/8/25
 * @Time: 上午10:41
 */

/**
 * PorterDuff.Mode.DST_IN
 *          计算方式：[Sa * Da, Sa * Dc]  ：只在源图像和目标图像相交的地方绘制目标图像
 *          最常见的应用就是蒙板绘制
 */
public class EraserView5 extends View {

    private static final int MIN_MOVE_DIS = 5; // 最小的移动距离;如果我们手指在屏幕上的移动距离小于5不绘制

    private Bitmap mFgBitmap, mBgBitmap; // 前景橡皮擦的bitmap和背景底图的Bitmap

    private Canvas mCanvas; // 绘制橡皮擦路径的画布

    private Paint mPaint; // 橡皮擦路径画笔

    private Path mPath; // 橡皮绘制路径

    private int screenW, screenH;

    private float preX, preY; // 记录上一个触摸事件的坐标位置

    public EraserView5(Context context) {
        this(context, null);

    }

    public EraserView5(Context context, AttributeSet attrs) {
        super(context, attrs);

        cal(context);
        initData(context);

    }

    private void initData(Context context) {
        mPath = new Path();

        // 设置画笔抗锯齿和抗抖动
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);

        // 设置画笔透明度为0是关键 让绘制的路径是透明的,然后让该路径与前景的底色混合"抠"出绘制路径
        mPaint.setARGB(128, 255, 0, 0);
        // 设置混合模式为DST_IN
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        // 设置画笔风格为描边
        mPaint.setStyle(Paint.Style.STROKE);

        // 设置路径结合处样式
        mPaint.setStrokeJoin(Paint.Join.ROUND);

        // 设置笔触类型
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        // 设置描边宽度
        mPaint.setStrokeWidth(50);

        // 生成前景图Bitmap
        mFgBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_8888);

        // 将其注入画布
        mCanvas = new Canvas(mFgBitmap);

        // 绘制画布背景灰色
        mCanvas.drawColor(0xFF808080);

        // 获取背景底图Bitmap
        mBgBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.a4);

        // 缩放背景底图Bitmap至屏幕大小
        mBgBitmap = Bitmap.createScaledBitmap(mBgBitmap, screenW, screenH, true);

    }

    private void cal(Context context) {
        screenW = context.getResources().getDisplayMetrics().widthPixels;
        screenH = context.getResources().getDisplayMetrics().heightPixels;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制背景
        canvas.drawBitmap(mBgBitmap, 0, 0, null);

        // 绘制前景
        canvas.drawBitmap(mFgBitmap, 0, 0, null);

        /**
         * canvas和mCanvas是两个不同的画布对象
         * 当我们在屏幕上移动手指绘制路径时会把路径通过mCanvas绘制到mFgBitmap上
         * 每当我们手指移动一次均会将路径mPath作为目标图像绘制mCanvas上,而在上面我们先在mCanvas上绘制了灰色
         * 两者会因为DST_IN模式的计算只显示中性灰,但是因为mPath的透明,计算生成的混合图像也会是透明的,
         * 所以会得到"橡皮擦"的效果
         */
        mCanvas.drawPath(mPath, mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN: // 手指接触屏幕重置路径
                mPath.reset();
                mPath.moveTo(x, y);
                preX = x;
                preY = y;
                break;

            case MotionEvent.ACTION_MOVE: // 手指移动时连接路径
                float dx = Math.abs(x - preX);
                float dy = Math.abs(y - preY);
                if (dx >= MIN_MOVE_DIS || dy >= MIN_MOVE_DIS) {
                    mPath.quadTo(preX, preY, (x + preX) / 2, (y + preY) / 2);
                    preX = x;
                    preY = y;
                }

                break;

        }

        invalidate();

        return true;
    }
}
